package com.xxxtea.component;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.xxxtea.common.UserContext;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Web请求日志切面
 * 
 * 通过AOP拦截所有Controller层的请求，记录请求URL、用户信息、参数等日志，便于接口调试和问题追踪。
 * 支持自动识别@RequestBody、文件上传、排除HttpServletRequest/Response等特殊参数。
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
@Aspect
@Component
public class WebRequestAspect {

	/**
	 * 前置通知，拦截所有controller包下的方法
	 * 记录请求URL、用户信息、参数等日志
	 * @param joinPoint 切点
	 */
	@Before("execution(* com.xxxtea.controller..*(..))")
	public void before(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		ApiOperation annotation = method.getAnnotation(ApiOperation.class);
		RequestMapping mapping = AnnotationUtil.getAnnotation(method, RequestMapping.class);
		if (annotation == null || mapping == null) {
			return;
		}
		// 获取当前请求对象
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		if (attributes == null) {
			return;
		}

		HttpServletRequest request = attributes.getRequest();
		List<String> msgList = new ArrayList<>();
		msgList.add(StrUtil.format("requestUrl: [{}]", request.getRequestURI()));
		if (UserContext.isLogin()) {
			msgList.add(StrUtil.format("user: [{}@{}]", UserContext.getId(), UserContext.getUser().getNickname()));
		}
		if (getRequestParamString(joinPoint) != null) {
			msgList.add("params: " + getRequestParamString(joinPoint));
		}
		log.info(String.join(", ", msgList));
	}

	/**
	 * 获取请求参数字符串（支持@RequestBody、文件上传、排除HttpServletRequest/Response）
	 * @param joinPoint 切点
	 * @return 参数JSON字符串
	 */
	private String getRequestParamString(JoinPoint joinPoint) {
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		String[] paramNames = signature.getParameterNames();
		Object[] paramValues = joinPoint.getArgs();
		if (paramNames == null || paramNames.length == 0) {
			return null;
		}
		Parameter[] parameters = signature.getMethod().getParameters();
		if (parameters.length == 1 && parameters[0].isAnnotationPresent(RequestBody.class)) {
			return JSON.toJSONString(paramValues[0]);
		}

		Map<String, Object> params = new LinkedHashMap<>();
		for (int i = 0; i < paramNames.length; i++) {
			Object value = paramValues[i];
			if (value instanceof HttpServletResponse || value instanceof HttpServletRequest) {
				continue;
			}
			if (value instanceof MultipartFile) {
				MultipartFile file = (MultipartFile) value;
				params.put(paramNames[i], file.getOriginalFilename());
			} else {
				params.put(paramNames[i], value);
			}
		}
		return JSON.toJSONString(params);
	}
}
